<template>
  <Modal :active="freeBodyModalVueActive" modal-class="freebody" transfer title="FreeBody功能卡" hide-mask draggable
    :width="540" :no-footer="true" @close="closeBtn">
    <div class="wrapper">
      <div class="title">
        <div class="title_color"></div>
        <div class="title_content">选项</div>
      </div>
      <div class="pd_l mg_b">
        <RadioGroup v-model:value="formFreeBodyModalVue.var" :options="optionList" @change="onChangeVar" />
      </div>
      <div class="form-item mg_b pd_r">
        <div class="form-label">op2/xdb file:</div>
        <div class="form-content">
          <Input v-model:value="formFreeBodyModalVue.fileName" style="width: 300px;" clearable />
          <div class="upload mg_l_sm">
            <input class="upload-input" type="file" accept=".op2" ref="upload" @change="handleUploadChange" />
            <Button class="upload-btn" type="default" :loading="uploading" @click="onClickUpload">打开</Button>
          </div>
        </div>
      </div>
      <div class="title">
        <div class="title_color"></div>
        <div class="title_content">载荷步</div>
      </div>
      <div class="pd_l mg_b_sm flex_box pd_r">
        <RadioGroup v-model:value="loadStepValue" :options="loadStepList" />
        <ButtonGroup size="small">
          <Button @click="selectSubcaseId(1)">全选</Button>
          <Button @click="selectSubcaseId(0)">取消</Button>
          <Button @click="selectSubcaseId(-1)">反选</Button>
        </ButtonGroup>
      </div>
      <div class="pd_l mg_b pd_r">
        <select multiple v-model="formFreeBodyModalVue.selected_subcase_ids" class="select">
          <option v-for="item in formFreeBodyModalVue.subcase_ids" :key="item">{{ item }}</option>
        </select>
      </div>
      <div class="title">
        <div class="title_color"></div>
        <div class="title_content">选择器</div>
      </div>
      <div class="form-item mg_b">
        <div class="form-label">选择单元集:</div>
        <div>
          <div class="selector-buttons mg_b_sm">
            <!-- 点击后打开Set列表，选择后执行updateEntity命令 -->
            <button class="selector-button active" @click="handleSelectEntities">
              {{ formFreeBodyModalVue.checkedSets.length }} Element Set (s)
            </button>
            <button class="selector-button icon-button">
              <img src="../assets/delete.svg" alt="" class="icon imgStyle" />
            </button>
          </div>
          <div v-show="formFreeBodyModalVue.var == 'displacements'">
            <Checkbox v-model:checked="formFreeBodyModalVue.autoFindInterfaceNodes" @change="handleFindinterfaceNodes">
              自动寻找接触点</Checkbox>
          </div>
        </div>
      </div>
      <div v-show="formFreeBodyModalVue.var == 'displacements'">
        <div class="form-item mg_b">
          <div class="form-label">节点集名称:</div>
          <div>
            <Input v-model:value="formFreeBodyModalVue.nodeSetName" clearable />
          </div>
        </div>
        <div class="form-item mg_b" v-show="!formFreeBodyModalVue.autoFindInterfaceNodes">
          <div class="form-label">选择节点:</div>
          <div>
            <div class="selector-buttons mg_b_sm">
              <button class="selector-button active" @click="handleNodeCheck">Nodes</button>
              <button class="selector-button icon-button">
                <img src="../assets/delete.svg" alt="" class="icon imgStyle" />
              </button>
            </div>
          </div>
        </div>
      </div>
      <div v-show="formFreeBodyModalVue.var == 'force'">
        <div class="form-item mg_b" v-show="!formFreeBodyModalVue.autoFindInterfaceNodes">
          <div class="form-label">选择Sum节点:</div>
          <div>
            <div class="selector-buttons mg_b_sm">
              <button class="selector-button active">Node</button>
              <button class="selector-button icon-button">
                <img src="../assets/delete.svg" alt="" class="icon imgStyle" />
              </button>
            </div>
          </div>
        </div>
      </div>
      <!-- <div class="pd_l">
          <Checkbox v-model:checked="displayModel" @change="handleDisplayModel">显示模型</Checkbox>
        </div> -->
      <div class="title">
        <div class="title_color"></div>
        <div class="title_content">输出选项</div>
      </div>
      <div class="pd_l mg_b">
        <Space :size="32">
          <Checkbox v-model:checked="formFreeBodyModalVue.showSummary">
            显示汇总表
          </Checkbox>
          <Checkbox v-model:checked="formFreeBodyModalVue.createLoadBCs">
            创建载荷/约束
          </Checkbox>
        </Space>
      </div>
    </div>
    <div class="foot-box">
      <Button type="default" v-if="formFreeBodyModalVue.summary.length > 0"
        @click="summaryModal.open = true">查看汇总表</Button>
      <Button type="primary" :loading="applying" @click="confirm">应用</Button>
      <Button type="default" @click="closeBtn">取消</Button>
    </div>
  </Modal>
  <Modal v-model:active="setsModalOpen" :width="340" transfer hide-mask draggable title="选择单元集" confirm-text="应用"
    @cancel="setsModalOpen = false" @confirm="handleSelectedSets">
    <Spin :active="setsSpinning" tip="加载中...">
      <CheckboxGroup v-model:value="formFreeBodyModalVue.checkedSets" control vertical>
        <Checkbox v-for="item in formFreeBodyModalVue.sets" :key="item.id" :label="item.name" :value="item.id">
        </Checkbox>
      </CheckboxGroup>
    </Spin>
  </Modal>
  <Modal modal-class="outputs" v-model:active="summaryModal.open" :width="928" :top="90" transfer hide-mask draggable
    title="Output Summary Table" no-footer>
    <Spin :active="summaryModal.loading" tip="加载中...">
      <div v-if="!formFreeBodyModalVue.summary">暂无数据</div>
      <div v-else v-for="tb in formFreeBodyModalVue.summary" :key="tb.subcase_id">
        <Title :level="5" style="">
          subcase_id: {{ tb.subcase_id }}
        </Title>
        <Table :data="tb.source" :border="true" :width="900" :height="500" use-x-bar use-y-bar virtual>
          <TableColumn id-key="nodeId" name="Node ID"></TableColumn>
          <TableColumn id-key="data1" :name="formFreeBodyModalVue.var == 'force' ? 'Fx' : 'Ux'"></TableColumn>
          <TableColumn id-key="data2" :name="formFreeBodyModalVue.var == 'force' ? 'Fy' : 'Uy'"></TableColumn>
          <TableColumn id-key="data3" :name="formFreeBodyModalVue.var == 'force' ? 'Fz' : 'Uz'"></TableColumn>
          <TableColumn id-key="data4" :name="formFreeBodyModalVue.var == 'force' ? 'Mx' : 'Rx'"></TableColumn>
          <TableColumn id-key="data5" :name="formFreeBodyModalVue.var == 'force' ? 'My' : 'Ry'"></TableColumn>
          <TableColumn id-key="data6" :name="formFreeBodyModalVue.var == 'force' ? 'Mz' : 'Rz'"></TableColumn>
        </Table>
      </div>
    </Spin>
    <div class="foot-box">
      <Button type="default" @click="summaryModal.open = false">关闭</Button>
    </div>
  </Modal>
</template>
<script setup lang="ts">
import { ref, reactive, onMounted, watch } from "vue";
import {
  Modal,
  Button,
  Input,
  Checkbox,
  RadioGroup,
  Space,
  ButtonGroup,
  CheckboxGroup,
  Toast,
  Message,
  Table,
  TableColumn,
  Title,
  Notice,
  Divider
} from "cax-ui";
import {
  S3Client,
  HeadObjectCommand,
  PutObjectCommand,
} from "@aws-sdk/client-s3";
import { Buffer } from "buffer";
import { oss, Bucket } from "@/UI/config";
import { useCoreStore, _global } from "@/UI/store";
import { storeToRefs } from "pinia";
import { FreebodyEntity, FreebodyFindNodesOptions, STATUS_CODE } from "@/FrontProcessing";

const coreStore = useCoreStore();
const { freeBodyModalVueActive } = storeToRefs(coreStore);

let s3Client: any = null;
const upload = ref();
const uploading = ref(false); // op2 文件上传中
const applying = ref(false);  // 应用中

const setsModalOpen = ref(false) // 选择单元集，单元集弹窗open
const setsSpinning = ref(false)
// 汇总表弹窗
const summaryModal = reactive<{
  open: boolean;
  loading: boolean;  // 汇总表数据加载中
}>({
  open: false,
  loading: false,
})
// 汇总表数据格式
type SummarySourceItem = {
  subcase_id: number;
  source: Array<{ nodeId: number;[key: string]: number }>;
}
const formFreeBodyModalVue = reactive<{
  setName: string;
  var: string;                        // 选项：位移、力
  fileName: string;                   // op2文件上传后返回的本地临时文件路径
  subcase_ids: Array<string>;         // op2文件上传后返回的数据，载荷步多选列表的选项
  selected_subcase_ids: string[];     // 选中的载荷步数据
  sets: { id: number; name: string; }[];// 单元集sets数据
  checkedSets: number[];              // 选中的sets
  nodeSetName: string;                // 节点集名称（位移的时候显示）
  summary: Array<SummarySourceItem>;  // 汇总表数据
  autoFindInterfaceNodes: boolean;    // 选择器- 自动寻找接触点（位移的时候显示）
  showSummary: boolean;               // 输出选项- 显示汇总表
  createLoadBCs: boolean;             // 输出选项- 创建载荷/约束
}>({
  setName: 'FreeBody',
  var: 'displacements',
  fileName: '',
  subcase_ids: [],
  selected_subcase_ids: [],
  sets: [],
  checkedSets: [],
  summary: [],
  autoFindInterfaceNodes: false,
  nodeSetName: 'nodeset01',
  showSummary: true,
  createLoadBCs: true,
});
let interfaceNodes = []

const optionList = [{ content: "位移", label: 'displacements' }, { content: "力", label: 'force' }];
const loadStepValue = ref("id")
const loadStepList = ref([{ content: "仅ID", label: "id" }, { content: "ID和名字", label: "id-name" }]);

const onChangeVar = () => {
  const maxNumSelection = formFreeBodyModalVue.var === 'displacements' ? 0 : 1
  const setName = formFreeBodyModalVue.var === 'displacements' ? 'FreeBody' : 'FreeBodyNode'
  _global.Engine.freebody.enter({ maxNumSelection, setName })
}

// 选择单元集-应用
function handleSelectedSets() {
  const entities: FreebodyEntity[] = formFreeBodyModalVue.sets.map(item => ({
    ...item,
    check: formFreeBodyModalVue.checkedSets.includes(item.id) ? 'true' : 'false'
  }))
  _global.Engine.freebody.update_entities(entities)
    .then(res => {
      console.log('---- update_entities res: ', res)
      formFreeBodyModalVue.var === 'force' && handleFindinterfaceNodes(true)
      setsModalOpen.value = false
    })
    .catch(err => {
      console.log('---- update_entities err: ', err)
    })
}
function handleFindinterfaceNodes(checked: boolean) {
  // 自动寻找接触点时执行process
  const params: FreebodyFindNodesOptions = {
    "isfind": checked ? 1 : 0,
    "var": formFreeBodyModalVue.var
  }
  _global.Engine.freebody.find_nodes(params)
    .then(res => {
      // console.log('--- find interface nodes: ', res)
      if (!checked && interfaceNodes.length) {
        // 取消自动寻找的接触点
        interfaceNodes.forEach(point => {
          _global.Engine.model.remove(point)
        })
      }
      interfaceNodes = res
    })
    .catch(err => {
      console.log('--- find interface nodes err: ', err)
    })
}

function handleSelectEntities() {
  // 选择单元集：打开sets选项
  setsModalOpen.value = true;
  setsSpinning.value = true
  _global.Engine.freebody.sets()
    .then(res => {
      if (!res || !res.ids) {
        Notice.error("未获取到Sets数据: ", res);
        return
      }
      formFreeBodyModalVue.sets = res["ids"].map((id: number, index: number) => ({ id, name: res["names"][index] }));
    })
    .finally(() => {
      setsSpinning.value = false;
    })
}

function handleNodeCheck() {
  _global.Engine.state.set("Mode", STATUS_CODE.VERTEX_SELECT);
  _global.Engine.registerSelectPointRightClick();
}

function confirm() {
  applying.value = true
  const { selected_subcase_ids, nodeSetName, fileName, autoFindInterfaceNodes, createLoadBCs, showSummary } = formFreeBodyModalVue
  _global.Engine.freebody.apply({
    fileName,
    nodeSetName,
    selected_subcase_ids,
    var: formFreeBodyModalVue.var,
    autoFindInterfaceNodes: formFreeBodyModalVue.var === 'force' ? 1 : (autoFindInterfaceNodes ? 1 : 0),
    createLoadBCs: createLoadBCs ? 1 : 0,
    showSummary: showSummary ? 1 : 0
  }).then(res => {
    applying.value = false
    // console.log('--- free body apply: ', res)
    if (showSummary) {
      // 显示汇总表
      summaryModal.open = true
    }
    summaryModal.loading = true
    _global.Engine.freebody.table_data({ fileName, var: formFreeBodyModalVue.var, createLoadBCs })
      .then(content => {
        // console.log('--- free body content: ', content)
        summaryModal.loading = false
        if (content.op2Info) {
          // console.log('--- content.op2Info: ', content.op2Info)
          const summary: SummarySourceItem[] = content.op2Info.map(item => {
            return {
              subcase_id: item.subcase_id,
              source: item.nodeId.map((nodeId, index) => ({
                nodeId,
                data1: item.data1[index],
                data2: item.data2[index],
                data3: item.data3[index],
                data4: item.data4[index],
                data5: item.data5[index],
                data6: item.data6[index],
              }))
            }
          })
          formFreeBodyModalVue.summary = summary
        } else {
          formFreeBodyModalVue.summary = []
        }
      })
    if (interfaceNodes.length) {
      // 取消自动寻找的接触点
      interfaceNodes.forEach(point => {
        _global.Engine.model.remove(point)
      })
      interfaceNodes = []
    }
  }).catch(err => {
    applying.value = false
    console.log('--- free body apply err: ', err)
    Notice.error('应用失败')
  })
  // freeBodyModalVueActive.value = false;
}

const selectSubcaseId = (val: -1 | 0 | 1) => {
  let subcaseIds = [];
  if (val == -1) {
    // 反选
    subcaseIds = formFreeBodyModalVue.subcase_ids.filter(id => !formFreeBodyModalVue.selected_subcase_ids.includes(id))
  } else if (val == 1) {
    // 全选    
    subcaseIds = [...formFreeBodyModalVue.subcase_ids]
  }
  formFreeBodyModalVue.selected_subcase_ids = subcaseIds
}

const onClickUpload = () => {
  upload.value.click();
}

const readFileAsArrayBuffer = (file: File): Promise<ArrayBuffer> => {
  return new Promise((resolve, reject) => {
    const reader = new FileReader();
    reader.onload = () => resolve(reader.result as ArrayBuffer);
    reader.onerror = reject;
    reader.readAsArrayBuffer(file);
  });
};
// 上传文件到 MinIO
const uploadFile = async (file: any, bucketName: string, objectKey: string) => {
  const command = new PutObjectCommand({
    Bucket: bucketName,
    Key: objectKey,
    Body: file,
  });
  try {
    const response = await s3Client.send(command);
    return {
      Location: `${location.href.includes("dev") ? "http://127.0.0.1:9000" : oss().endpoint
        }/${Bucket()}/${objectKey}`,
    };
  } catch (error) {
    alert(`文件上传失败，请重试。${error}`);
    return;
  }
};
// 检查文件是否存在
const checkIfFileExists = async (bucketName: string, objectKey: string) => {
  try {
    const command = new HeadObjectCommand({
      Bucket: bucketName,
      Key: objectKey,
    });
    await s3Client.send(command);
    return true;
  } catch (error: any) {
    if (error.name === "NotFound") {
      return false;
    }
    throw error;
  }
};

async function loadStpOrBdfFile(arrayBuffer: ArrayBuffer, filename: string) {
  Toast.loading({ content: "上传中", duration: 0 });
  let key = `export/${filename}`;
  const fileExists = await checkIfFileExists(Bucket(), key);
  console.log("fileExists", fileExists);
  if (!fileExists) {
    const buffer = Buffer.from(arrayBuffer);
    const uploadResponse = await uploadFile(buffer, Bucket(), key);
  }
  const path = `${oss().endpoint}/${Bucket()}/${key}`;
  Toast.close();
  return path;
}

async function handleUploadChange(event: any) {
  const files: File[] = event?.target?.files
  const file = files[0]
  if (!file) return
  const fileName = file.name;
  let arrayBuffer: ArrayBuffer = await readFileAsArrayBuffer(file);
  const path = await loadStpOrBdfFile(arrayBuffer, fileName);
  if (!path) {
    Message.error('上传失败')
    return
  }
  uploading.value = true;
  _global.Engine.freebody.read_file({ path })
    .then(res => {
      formFreeBodyModalVue.subcase_ids = res.subcase_ids.map(id => `${id}`);
      formFreeBodyModalVue.fileName = res.fileName;
      uploading.value = false;
    })
    .catch(err => {
      console.log('---- freebody err: ', err)
      uploading.value = false;
    })
}

watch(freeBodyModalVueActive, (show) => {
  if (show) {
    const maxNumSelection = formFreeBodyModalVue.var === 'displacements' ? 0 : 1
    const setName = formFreeBodyModalVue.var === 'displacements' ? 'FreeBody' : 'FreeBodyNode'
    _global.Engine.freebody.enter({ maxNumSelection, setName })

  }
})
function closeBtn() {
  coreStore.setFreeBodyModalVueValue({ ...formFreeBodyModalVue });
  freeBodyModalVueActive.value = false;
  _global.Engine.freebody.leave()
  _global.Engine.state.set("Mode", STATUS_CODE.NORMAL);
  _global.Engine.unregisterSelectPointRightClick(); // 注销 selectPoint 右键鼠标事件
  _global.Engine.registerNormalRightClick(); // 注册normal右键鼠标事件
}
onMounted(() => {
  s3Client = new S3Client(oss());
});
</script>
<style scoped>
.selector-buttons {
  display: flex;
  justify-content: flex-start;
  align-items: center;
}

.selector-button {
  height: 32px;
  width: 200px;
  padding: 0 15px;
  border: 1px solid #ccc;
  background-color: #fff;
  cursor: pointer;
  outline: none;
}

.selector-button.active {
  background-color: #e6f7a7;
  border-top-left-radius: 4px;
  border-bottom-left-radius: 4px;
  /* flex-grow: 1; */
  font-weight: normal;
}

.icon-button {
  width: 32px;
  padding: 3px 5px;
  display: flex;
  justify-content: center;
  align-items: center;
  border-top-right-radius: 4px;
  border-bottom-right-radius: 4px;
  border-left: none;
  background-color: #fff;
}

.icon-arrow {
  display: inline-block;
  width: 16px;
  height: 16px;
  position: relative;
}

.icon-arrow::before {
  content: "";
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  width: 0;
  height: 0;
  border-left: 5px solid transparent;
  border-right: 5px solid transparent;
  border-top: 5px solid #1e88e5;
}

.imgStyle {
  width: 100%;
  height: 100%;
}

.title {
  display: flex;
  align-items: center;
  width: 100%;
  padding: 0 16px;
  margin-bottom: 16px;

  .title_color {
    width: 4px;
    height: 12px;
    background: #339af0;
    margin-right: 8px;
  }

  .title_content {
    opacity: 1;
    font-family: PingFang SC;
    font-size: 14px;
    font-weight: 600;
    line-height: 22px;
    letter-spacing: 0em;
    font-variation-settings: "opsz" auto;
    /* content/主要一级primary */
    /* 样式描述：--vxp-content-color-primary */
    color: #212529;
  }
}

.foot-box {
  width: 100%;
  padding: 16px;
  border-top: solid 1px var(--vxp-border-color-light-1);
  text-align: right;
}

.pd_l {
  margin-left: 22%;
}

.mg_b {
  margin-bottom: 20px;
}

.mg_b_sm {
  margin-bottom: 8px;
}

.mg_l_sm {
  margin-left: 8px;
}

.pd_r {
  padding-right: 12px;
}

.flex_box {
  display: flex;
  align-items: center;
  justify-content: space-between;
}

.flex_box :deep(.vxp-button--small) {
  --vxp-button-min-width: 42px;
}

.form-item {
  display: flex;
}

.form-label {
  width: 8.4em;
  height: 30px;
  margin-right: 12px;
  text-align: right;
  line-height: 30px;
}

.form-content {
  display: flex;
  flex: 1;
}

.radio_item {
  display: inline-block;
  width: 4.5em;
}

.buttonStyle {
  min-width: 24px;
  height: 24px;
  line-height: 30px;
  padding: 5px 10px;
}

.select {
  width: 100%;
  height: 6em;
  padding: 4px 0;
  border-color: var(--vxp-border-color-light-1);
}

.select:focus {
  outline: none;
}

.select option {
  padding: 4px 8px;
}

.wrapper {
  max-height: calc(100vh - 120px);
  padding: 12px;
  overflow: auto;
  scrollbar-color: #f0f0f0;
}

.upload {
  position: relative;
  display: inline-block;
  overflow: hidden;
}

.upload-input {
  position: absolute;
  left: 0;
  top: 0;
  width: 100%;
  height: 100%;
  opacity: 0;
  z-index: -1;
  visibility: hidden;
}
</style>
<style>
.freebody .vxp-modal__content {
  padding: 0;
}

.outputs .vxp-modal__content {
  padding-top: 0;
}
.outputs .foot-box {
  padding: var(--vxp-modal-body-v-padding) 0 0;
}

.sets-box {
  margin-top: 12px;
}

.sets-box .vxp-checkbox {
  margin: 4px 0;
}
</style>